package org.sean.framework.util;


import java.security.SecureRandom;

/**
 * Date: 2016/11/12 11:34
 *
 * @author Sean.xie
 */
public class NumberUtil {
    /**
     * All possible chars for representing a number as a String
     */
    private static final char[] DIGITS = {
            '0', '1', '2', '3', '4', '5',
            '6', '7', '8', '9', 'a', 'b',
            'c', 'd', 'e', 'f', 'g', 'h',
            'i', 'j', 'k', 'l', 'm', 'n',
            'o', 'p', 'q', 'r', 's', 't',
            'u', 'v', 'w', 'x', 'y', 'z',
            'A', 'B', 'C', 'D', 'E', 'F',
            'G', 'H', 'I', 'J', 'K', 'L',
            'M', 'N', 'O', 'P', 'Q', 'R',
            'S', 'T', 'U', 'V', 'W', 'X',
            'Y', 'Z',
    };

    private static final char[] CHINESE_NUM = {'零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'};
    private static final char[] CHINESE_UNIT = {'里', '分', '角', '元', '拾', '佰', '仟', '万', '拾', '佰',
            '仟', '亿', '拾', '佰', '仟', '兆', '拾', '佰', '仟', '京', '拾', '佰', '仟', '垓', '拾', '佰', '仟',
            '秭', '拾', '佰', '仟', '穰', '拾', '佰', '仟', '沟', '拾', '佰', '仟', '涧', '拾', '佰', '仟',
            '正', '拾', '佰', '仟', '载', '拾', '佰', '仟', '极', '拾', '佰', '仟'};
    /**
     * DIGITS 对应的值
     */
    private static final byte[] VALUES;

    private static final int MIN_RADIX = 2;
    private static final int MAX_RADIX = 62;

    private static final SecureRandom RANDOM = new SecureRandom();

    static {
        // 初始化VALUES
        VALUES = new byte[128];
        for (int i = 0; i < 128; i++) {
            VALUES[i] = 0;
        }
        for (int i = 0; i < DIGITS.length; i++) {
            VALUES[DIGITS[i]] = (byte) (i);
        }
    }

    private NumberUtil() {
    }

    /**
     * 检查id 有效性
     *
     * @param id ID
     * @return 有效
     */
    public static boolean isValidId(Long id) {
        return (id != null && id > 0);
    }

    /**
     * 检查id 有效性
     *
     * @param id ID
     * @return 有效
     */
    public static boolean isValidId(Integer id) {
        return (id != null && id > 0);
    }

    /**
     * 检查id 有效性
     *
     * @param id ID
     * @return 无效
     */
    public static boolean isInValidId(Long id) {
        return (id == null || id <= 0);
    }

    /**
     * 检查id 有效性
     *
     * @param id ID
     * @return 无效
     */
    public static boolean isInValidId(Integer id) {
        return (id == null || id <= 0);
    }

    /**
     * 是否为正数
     *
     * @param number 数字
     * @return 是否为正数
     */
    public static boolean isPositive(Integer number) {
        return (number != null && number > 0);
    }

    /**
     * 是否为正数
     *
     * @param number 数字
     * @return 是否为正数
     */
    public static boolean isPositive(Byte number) {
        return (number != null && number > 0);
    }

    /**
     * 是否为正数
     *
     * @param number 数字
     * @return 是否为正数
     */
    public static boolean isPositive(Long number) {
        return (number != null && number > 0);
    }

    /**
     * 是否为负数
     *
     * @param number 数字
     * @return 是否为负数
     */
    public static boolean isNegative(Integer number) {
        return (number != null && number < 0);
    }

    /**
     * 是否为负数
     *
     * @param number 数字
     * @return 是否为负数
     */
    public static boolean isNegative(Byte number) {
        return (number != null && number < 0);
    }

    /**
     * 是否为负数
     *
     * @param number 数字
     * @return 是否为负数
     */
    public static boolean isNegative(Long number) {
        return (number != null && number < 0);
    }

    /**
     * 10以内随机数
     *
     * @return 随机数
     */
    public static int getRandomInTen() {
        return RANDOM.nextInt(10);
    }

    /**
     * 指定值以内随机数
     *
     * @param maxValue 最大值
     * @return 随机数
     */
    public static int getRandomInValue(int maxValue) {
        return RANDOM.nextInt(maxValue);
    }

    /**
     * 十进制字符串转化Long
     *
     * @param value 值
     * @return Long 值
     */
    public static Long getLong(String value) {
        if (StringUtil.isEmpty(value)) {
            return null;
        }
        try {
            return Long.valueOf(value);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 转换Long
     *
     * @param value        值
     * @param defaultValue 默认值
     * @return Long 值
     */
    public static long getLong(Long value, long defaultValue) {
        if (value == null) {
            return defaultValue;
        }
        return value;
    }

    /**
     * 对象转Long
     *
     * @param value 值
     * @return Long 值
     */
    public static Long getLongFromObj(Object value) {
        if (value == null) {
            return null;
        }
        if (value instanceof Number) {
            return ((Number) value).longValue();
        }
        return getLong(value.toString());
    }

    /**
     * 十进制字符串转化long
     *
     * @param value        值
     * @param defaultValue 默认值
     * @return long值
     */
    public static long getLong(String value, long defaultValue) {
        Double doubleValue = getDouble(value);
        long result = defaultValue;
        if (doubleValue != null) {
            result = doubleValue.longValue();
        }
        return result;
    }

    /**
     * 十进制字符串转换int
     *
     * @param value        值
     * @param defaultValue 默认值
     * @return Integer值
     */
    public static int getInteger(String value, int defaultValue) {
        Double doubleValue = getDouble(value);
        int result = defaultValue;
        if (doubleValue != null) {
            result = doubleValue.intValue();
        }
        return result;
    }

    /**
     * 转换int
     *
     * @param value        值
     * @param defaultValue 默认值
     * @return Integer值
     */
    public static int getInteger(Integer value, int defaultValue) {
        if (value != null) {
            return value;
        }
        return defaultValue;
    }

    /**
     * 对象转 int
     *
     * @param value        值
     * @param defaultValue 默认值
     * @return Integer值
     */
    public static int getIntegerFromObj(Object value, int defaultValue) {
        Integer iv = getIntegerFromObj(value);
        return iv == null ? defaultValue : iv;
    }

    /**
     * 对象转 Integer
     *
     * @param value 值
     * @return Integer值
     */
    public static Integer getIntegerFromObj(Object value) {
        if (value == null) {
            return null;
        }
        if (value instanceof Number) {
            return ((Number) value).intValue();
        }
        return getInteger(value.toString());
    }

    /**
     * 十进制字符串转换 Integer
     *
     * @param value 值
     * @return Integer值
     */
    public static Integer getInteger(String value) {
        if (StringUtil.isEmpty(value)) {
            return null;
        }
        try {
            return Integer.valueOf(value);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 转换 Double
     *
     * @param value        值
     * @param defaultValue 默认值
     * @return Double值
     */
    public static double getDouble(String value, double defaultValue) {
        Double result = getDouble(value);
        if (result == null) {
            result = defaultValue;
        }
        return result;
    }

    /**
     * 转换 Double
     *
     * @param value 值
     * @return Double值
     */
    public static Double getDouble(String value) {
        if (StringUtil.isEmpty(value)) {
            return null;
        }
        try {
            return Double.valueOf(value);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 转换 Float
     *
     * @param value        值
     * @param defaultValue 默认值
     * @return Float值
     */
    public static float getFloat(String value, float defaultValue) {
        Float result = getFloat(value);
        if (result == null) {
            result = defaultValue;
        }
        return result;
    }

    /**
     * 转换 Float
     *
     * @param value 值
     * @return Float值
     */
    public static Float getFloat(String value) {
        if (StringUtil.isEmpty(value)) {
            return null;
        }
        try {
            return Float.valueOf(value);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 转换为62进制
     *
     * @param value 值
     * @return 62进制数
     */
    public static String to62RadixString(long value) {
        return toRadixString(value, 62);
    }

    /**
     * 进制转换
     *
     * @param value 值
     * @param radix 进制
     * @return 进制值
     */
    public static String toRadixString(long value, int radix) {
        if (radix < MIN_RADIX || radix > MAX_RADIX) {
            radix = 10;
        }
        if (radix == 10) {
            return Long.toString(value);
        }
        char[] buf = new char[65];
        int charPos = 64;
        boolean negative = (value < 0);

        if (!negative) {
            value = -value;
        }

        while (value <= -radix) {
            buf[charPos--] = DIGITS[(int) (-(value % radix))];
            value = value / radix;
        }
        buf[charPos] = DIGITS[(int) (-value)];

        if (negative) {
            buf[--charPos] = '-';
        }

        return new String(buf, charPos, (65 - charPos));
    }

    /**
     * 字符串转换为long, 若超出范围则失败
     *
     * @param value 值
     * @param radix 进制
     * @return long值
     */
    public static long radixValue2Long(String value, int radix) {
        return parseLong(value, radix);
    }

    /**
     * 字符串转换为int ,安全算法,如果超int 范围则精度丢失
     *
     * @param value 值
     * @param radix 进制
     * @return int值
     */
    public static int radixValue2Int(String value, int radix) {
        return (int) radixValue2Long(value, radix);
    }

    /**
     * 字符串转换为int ,安全算法,如果超int 范围则失败
     *
     * @param value 值
     * @param radix 进制
     * @return int值
     */
    public static int radixValue2SafeInt(String value, int radix) {
        long result = radixValue2Long(value, radix);
        if (result > Integer.MAX_VALUE || result < Integer.MIN_VALUE) {
            throw forInputString(value);
        }
        return (int) result;
    }

    /**
     * 非十进制转为十进制
     *
     * @param value 非十进制字符串
     * @param radix 原始串进制数
     * @return 十进制数
     */
    public static long parseLong(String value, int radix) {
        if (value == null) {
            throw new NumberFormatException("null");
        }

        if (radix < MIN_RADIX) {
            throw new NumberFormatException("radix " + radix + " less than MIN_RADIX");
        }
        if (radix > MAX_RADIX) {
            throw new NumberFormatException("radix " + radix + " greater than MAX_RADIX");
        }

        long result = 0;
        boolean negative = false;
        int i = 0;
        int len = value.length();
        long limit = -Long.MAX_VALUE;
        long multmin;
        int digit;

        if (len > 0) {
            char firstChar = value.charAt(0);
            // Possible leading "+" or "-"
            if (firstChar < '0') {
                if (firstChar == '-') {
                    negative = true;
                    limit = Long.MIN_VALUE;
                } else if (firstChar != '+') {
                    throw forInputString(value);
                }
                // Cannot have lone "+" or "-"
                if (len == 1) {
                    throw forInputString(value);
                }
                i++;
            }
            multmin = limit / radix;

            while (i < len) {
                // Accumulating negatively avoids surprises near MAX_VALUE
                if (radix > Character.MAX_RADIX) {
                    digit = VALUES[value.charAt(i++)];
                } else {
                    digit = Character.digit(value.charAt(i++), radix);
                }
                if (digit < 0) {
                    throw forInputString(value);
                }
                if (result < multmin) {
                    throw forInputString(value);
                }
                result *= radix;
                if (result < limit + digit) {
                    throw forInputString(value);
                }
                result -= digit;
            }
        } else {
            throw forInputString(value);
        }
        return negative ? result : -result;
    }

    /**
     * 数字转换异常
     */
    private static NumberFormatException forInputString(String s) {
        return new NumberFormatException("For input string: \"" + s + "\"");
    }

    /**
     * @return 四位数字
     */
    public static String random() {
        StringBuilder str = new StringBuilder();
        str.append(RANDOM.nextInt(9) + 1);
        for (int i = 0; i < 3; i++) {
            str.append(RANDOM.nextInt(10));
        }
        return str.toString();
    }

    /**
     * 是否纯数字
     *
     * @param value 值
     * @return 是否是数字
     */
    public static boolean checkNum(String value) {
        return !StringUtil.isEmpty(value) && value.matches("\\d+");
    }

    /**
     * 比较 Integer
     *
     * @param v1 值1
     * @param v2 值2
     * @return 是否相同
     */
    public static boolean equals(Integer v1, Integer v2) {
        return !(v1 == null || v2 == null) && v1.equals(v2);
    }

    /**
     * 比较 Long
     *
     * @param v1 值1
     * @param v2 值2
     * @return 是否相同
     */
    public static boolean equals(Long v1, Long v2) {
        return !(v1 == null || v2 == null) && v1.equals(v2);
    }

    /**
     * 比较 Long
     *
     * @param v1 值1
     * @param v2 值2
     * @return 是否相同
     */
    public static boolean equals(Long v1, Integer v2) {
        return !(v1 == null || v2 == null) && v1.equals(v2.longValue());
    }

    /**
     * 比较 Float
     *
     * @param v1 值1
     * @param v2 值2
     * @return 是否相同
     */
    public static boolean equals(Float v1, Float v2) {
        float diff = 1e-6f;
        return !(v1 == null || v2 == null) && Math.abs(v1 - v2) < diff;
    }

    /**
     * 比较 Float
     *
     * @param v1 值1
     * @param v2 值2
     * @return 是否相同
     */
    public static boolean equals(Double v1, Double v2) {
        double diff = 1e-6D;
        return !(v1 == null || v2 == null) && Math.abs(v1 - v2) < diff;
    }


    /**
     * 差值
     *
     * @param v1 值1
     * @param v2 值2
     * @return 差值
     */
    public static Long delta(Long v1, Long v2) {
        if (v1 == null || v2 == null) {
            return null;
        }
        return v1 - v2;
    }

    /**
     * 差值
     *
     * @param v1 值1
     * @param v2 值2
     * @return 差值
     */
    public static Integer delta(Integer v1, Integer v2) {
        if (v1 == null || v2 == null) {
            return null;
        }
        return v1 - v2;
    }

    /**
     * 差值
     *
     * @param v1 值1
     * @param v2 值2
     * @return 差值
     */
    public static Long delta(Long v1, Integer v2) {
        if (v1 == null || v2 == null) {
            return null;
        }
        return v1 - v2;
    }


    /**
     * 返回关于钱的中文式大写数字,支仅持到亿
     *
     * @param price 金额
     * @return 大写人民币
     */
    public static String toRMB(int price) {
        return toRMB((double) price);
    }

    /**
     * 返回关于钱的中文式大写数字,支仅持到亿
     *
     * @param price 金额
     * @return 大写人民币
     */
    public static String toRMB(long price) {
        return toRMB((double) price);
    }

    /**
     * 整数位支持12位,到仟亿
     * 支持到小数点后3位,如果大于3位,那么会四舍五入到3位
     *
     * @param price 金额,最小单位厘
     * @return 大写人民币
     */
    public static String toRMB(double price) {
        String res = "";
        String money = String.format("%.3f", price);
        int i = 0;
        if (price == 0.0) {
            return "零元";
        }
        String inte = money.split("\\.")[0];
        int deci = Integer.parseInt(money.split("\\.")[1].substring(0, 3));
        while (deci > 0) {
            res = CHINESE_UNIT[i++] + res;
            res = CHINESE_NUM[deci % 10] + res;
            deci /= 10;
        }
        res = res.replaceAll("零[里分角]", "零");
        if (i < 3) {
            res = "零" + res;
        }
        res = res.replaceAll("零+", "零");
        if (res.endsWith("零")) {
            res = res.substring(0, res.length() - 1);
        }
        return toRMB(inte) + res;
    }

    /**
     * 返回关于钱的中文式大写数字,支仅持到亿
     *
     * @param price 金额,最小单位元
     * @return 大写人民币
     * @throws NumberFormatException 数值格式化异常
     */
    public static String toRMB(String price) {
        String res = "";
        int i = 3;
        int len = price.length();
        if (len > CHINESE_UNIT.length - 3) {
            throw new IllegalArgumentException("price too large!");
        }
        if ("0".equals(price)) {
            return "零元";
        }
        for (len--; len >= 0; len--) {
            res = CHINESE_UNIT[i++] + res;
            int num = Integer.parseInt(price.charAt(len) + "");
            res = CHINESE_NUM[num] + res;
        }
        return res.replaceAll("零[拾佰仟]", "零")
                .replaceAll("零+亿", "亿").replaceAll("零+万", "万")
                .replaceAll("零+元", "元").replaceAll("零+", "零");

    }
}
